﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;

namespace OthelloCognition
{
    #region INSTANCES add your solvers here 2 Places!!!!!!!
    //#1         You can make any description and any value you wish, just reference it in the Sovlver Interface you Implement
    public enum SolverEnum
    {
        [EnumDescription("HUMAN PLAYER")] 
        Human,
        [EnumDescription("RANDOM SOLVER")]
        Random,
        [EnumDescription("GREEDY SCORE")]
        GreedyScore,
        [EnumDescription("GREEDY SMART SCORE")]
        GreedySmartScore,
        [EnumDescription("GREEDY MOBILITY")]
        GreedyMob,
        [EnumDescription("GREEDY STABILITY")]
        GreedyStab,
        [EnumDescription("NAIVE SOLVER")] 
        Naive,
        [EnumDescription("SCORE MINIMAX")]
        Scoremax,
        [EnumDescription("SMART SCORE MINIMAX")]
        SmartScoremax,
        [EnumDescription("MOBILITY MINIMAX")]
        Mobimax,
        [EnumDescription("MOBILITY+ MINIMAX")]
        Mobiplus,
        [EnumDescription("STABILITY MINIMAX")]
        Stabmax,
        [EnumDescription("Stab+Mob MINIMAX")]
        Mobstab,
        [EnumDescription("MAX(MOB,STAB) MINIMAX")]
        MoSt,
        [EnumDescription("HALF-STABILITY MINIMAX")]
        HalfStabmax,
        [EnumDescription("DENY-STABILITY MINIMAX")]
        DenyStabmax,
        [EnumDescription("SCORE AB-PRUNING")]
        ScoreAB,
        [EnumDescription("SMART SCORE AB-PRUNING")]
        SmartScoreAB,
        [EnumDescription("MOBILITY AB-PRUNING")]
        MobAB,
        [EnumDescription("MOBILITY+ AB-PRUNING")]
        MobplusAB,
        [EnumDescription("STABILITY AB-PRUNING")]
        StabAB,
        [EnumDescription("Stab+Mob AB-PRUNING")]
        MobstabAB,
        [EnumDescription("MAX(MOB,STAB) AB-PRUNING")]
        MoStAB,
        [EnumDescription("HALF-STABILITY AB-PRUNING")]
        HalfStAB,
        [EnumDescription("DENY-STABILITY AB-PRUNING")]
        DenyStAB,
        [EnumDescription("MINIMAX-VG SOLVER")]
        MinimaxVG,
        [EnumDescription("SCORE NEGAMAX")]
        ScoreABVG,
        [EnumDescription("SMART SCORE NEGAMAX")]
        SmartScoreABVG,
        [EnumDescription("MOBILITY NEGAMAX")]
        MobABVG,
        [EnumDescription("MOBILITY+ NEGAMAX")]
        MobplusABVG,
        [EnumDescription("STABILITY NEGAMAX")]
        StabABVG,
        [EnumDescription("Stab+Mob NEGAMAX")]
        MobstabABVG,
        [EnumDescription("MAX(MOB,STAB) NEGAMAX")]
        MoStABVG,
        [EnumDescription("HALF-STABILITY NEGAMAX")]
        HalfStABVG,
        [EnumDescription("DENY_STABILITY NEGAMAX")]
        DenyStABVG 

    }

    //#2         YOU MUST ADD YOUR SOLVER IN HERE AS WELL.
    public static class NewSolver
    {
        public static AbstractSolver NewSolverConstructor(SolverEnum enumOfSolverToMake)
        {
            switch (enumOfSolverToMake)
            {
                case SolverEnum.Human:          return new HumanPlayer();
                case SolverEnum.Random:         return new RandomSolver();
                case SolverEnum.Naive:          return new NaiveSolver();
                case SolverEnum.GreedyScore:    return new GreedySolver(Heuristics.Score);
                case SolverEnum.GreedySmartScore: return new GreedySolver(Heuristics.SmartScore);
                case SolverEnum.GreedyMob:      return new GreedySolver(Heuristics.Mobplus);
                case SolverEnum.GreedyStab:     return new GreedySolver(Heuristics.Stability);
                case SolverEnum.Scoremax:       return new MinmaxSolver(Heuristics.Score);
                case SolverEnum.SmartScoremax:  return new MinmaxSolver(Heuristics.SmartScore);
                case SolverEnum.Mobimax:        return new MinmaxSolver(Heuristics.Mobility);
                case SolverEnum.Mobiplus:       return new MinmaxSolver(Heuristics.Mobplus);
                case SolverEnum.Stabmax:        return new MinmaxSolver(Heuristics.Stability);
                case SolverEnum.Mobstab:        return new MinmaxSolver(Heuristics.MoStSum);
                case SolverEnum.MoSt:           return new MinmaxSolver(Heuristics.MoStMax);
                case SolverEnum.HalfStabmax:    return new MinmaxSolver(Heuristics.HalfStable);
                case SolverEnum.DenyStabmax:    return new MinmaxSolver(Heuristics.DenyStable);
                case SolverEnum.ScoreAB:        return new AlphaBetaSolver(Heuristics.Score);
                case SolverEnum.SmartScoreAB:   return new AlphaBetaSolver(Heuristics.SmartScore);
                case SolverEnum.MobAB:          return new AlphaBetaSolver(Heuristics.Mobility);
                case SolverEnum.MobplusAB:      return new AlphaBetaSolver(Heuristics.Mobplus);
                case SolverEnum.StabAB:         return new AlphaBetaSolver(Heuristics.Stability);
                case SolverEnum.MobstabAB:      return new AlphaBetaSolver(Heuristics.MoStSum);
                case SolverEnum.MoStAB:         return new AlphaBetaSolver(Heuristics.MoStMax);
                case SolverEnum.HalfStAB:       return new AlphaBetaSolver(Heuristics.HalfStable);
                case SolverEnum.DenyStAB:       return new AlphaBetaSolver(Heuristics.DenyStable);
                case SolverEnum.MinimaxVG:      return new MinmaxSolverVG(Heuristics.Score);
                case SolverEnum.ScoreABVG:      return new ABPruneSolverVG(Heuristics.Score);
                case SolverEnum.SmartScoreABVG: return new ABPruneSolverVG(Heuristics.SmartScore);
                case SolverEnum.MobABVG:        return new ABPruneSolverVG(Heuristics.Mobility);
                case SolverEnum.MobplusABVG:    return new ABPruneSolverVG(Heuristics.Mobplus);
                case SolverEnum.StabABVG:       return new ABPruneSolverVG(Heuristics.Stability);
                case SolverEnum.MobstabABVG:    return new ABPruneSolverVG(Heuristics.MoStSum);
                case SolverEnum.MoStABVG:       return new ABPruneSolverVG(Heuristics.MoStMax);
                case SolverEnum.HalfStABVG:       return new ABPruneSolverVG(Heuristics.HalfStable);
                case SolverEnum.DenyStABVG:       return new ABPruneSolverVG(Heuristics.DenyStable);
                default: return null;
            }
        }
    }
    #endregion

    #region IGNORE!!!!
    /// <summary>
    /// Provides a description for an enumerated type.
    /// </summary>
    [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,
     AllowMultiple = false)]
    public sealed class EnumDescriptionAttribute : Attribute
    {
        private string description;

        /// <summary>
        /// Gets the description stored in this attribute.
        /// </summary>
        /// <value>The description stored in the attribute.</value>
        public string Description
        {
            get
            {
                return this.description;
            }
        }

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="EnumDescriptionAttribute"/> class.
        /// </summary>
        /// <param name="description">The description to store in this attribute.
        /// </param>
        public EnumDescriptionAttribute(string description)
            : base()
        {
            this.description = description;
        }
    }
   
   
    public static class EnumHelper
    {
       
        public static string GetDescription(this Enum value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            string description = value.ToString();
            FieldInfo fieldInfo = value.GetType().GetField(description);
            EnumDescriptionAttribute[] attributes =
               (EnumDescriptionAttribute[])
             fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);

            if (attributes != null && attributes.Length > 0)
            {
                description = attributes[0].Description;
            }
            return description;
        }

        
        public static IList<KeyValuePair<Enum, string>> ToList(this Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            //System.Collections.Generic.List
            List<KeyValuePair<Enum, string>> list = new List<KeyValuePair<Enum, string>>();
            Array enumValues = Enum.GetValues(type);

            foreach (Enum value in enumValues)
            {
                list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
            }

            return list;
        }
    }
    #endregion


}
